package homework.score.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.InputMismatchException;
import java.util.Scanner;
import java.util.regex.Pattern;

public class InputUtil {

    private InputUtil() {}

    public static String input() {
        return input(String.class);
    }

    public static String input(String prompt) {
        return input(String.class, prompt, null);
    }

    public static String input(String prompt, Pattern pattern, String errMsg) {
        String result = input(prompt);

        while (!pattern.matcher(result).matches()) {
            if (errMsg != null) {
                System.out.println(errMsg);
            }
            result = input(prompt);
        }

        return result;
    }

    public static <T> T input(Class<T> clazz) {
        return input(clazz, null, null);
    }

    public static <T> T input(Class<T> clazz, String prompt, String errMsg) {
        Object result = null;
        Scanner sc = new Scanner(System.in);

        while (result == null) {

            if (prompt != null) {
                System.out.print(prompt);
            }

            try {

                if (clazz == String.class) {
                    result = sc.nextLine();
                } else if(clazz == Integer.class || clazz == int.class) {
                    result = sc.nextInt();
                } else if(clazz == Float.class || clazz == float.class) {
                    result = sc.nextFloat();
                } else if(clazz == Long.class || clazz == long.class) {
                    result = sc.nextLong();
                } else if(clazz == Double.class || clazz == double.class) {
                    result = sc.nextDouble();
                } else if(clazz == Short.class || clazz == short.class) {
                    result = sc.nextShort();
                } else if(clazz == Byte.class || clazz == byte.class) {
                    result = sc.nextByte();
                } else if(clazz == BigInteger.class) {
                    result = sc.nextBigInteger();
                } else if(clazz == BigDecimal.class) {
                    result = sc.nextBigDecimal();
                } else if(clazz == Boolean.class || clazz == boolean.class) {
                    result = sc.nextBoolean();
                } else {
                    throw new IllegalArgumentException(clazz.getName());
                }

            } catch (InputMismatchException e) {

                if (errMsg != null) {
                    System.out.println(errMsg);
                }

                sc = new Scanner(System.in);
            }
        }

        return (T) result;
    }

    public static void inputBean(Object bean, String promptFmt, String errMsgFmt) {
        Field[] fields = bean.getClass().getDeclaredFields();

        for (Field field : fields) {
            String fieldName = field.getName();

            Method setter = ReflectionUtil.getSetter(bean, fieldName);

            if (setter == null) {
                continue;
            }

            Class[] classes = setter.getParameterTypes();

            String prompt = promptFmt;
            String errMsg = errMsgFmt;

            FieldName a = field.getAnnotation(FieldName.class);
            String annName = fieldName;
            if (a != null) {
                annName = a.value();

                if ("".equals(annName)) {
                    annName = fieldName;
                }
            }

            if (promptFmt.contains("%s")) {
                prompt = String.format(promptFmt, annName);
            }

            if (errMsgFmt.contains("%s")) {
                errMsg = String.format(errMsgFmt, annName);
            }

            Object value = InputUtil.input(classes[0], prompt, errMsg);

            try {
                setter.invoke(bean, value);
            } catch (IllegalAccessException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }

    }
}
